/*
 *  Licensed to the Apache Software Foundation (ASF) under one or more
 *  contributor license agreements.  See the NOTICE file distributed with
 *  this work for additional information regarding copyright ownership.
 *  The ASF licenses this file to You under the Apache License, Version 2.0
 *  (the "License"); you may not use this file except in compliance with
 *  the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package org.apache.coyote;

import java.io.IOException;
import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;

import org.apache.juli.logging.Log;
import org.apache.tomcat.util.net.AbstractEndpoint.Handler.SocketState;
import org.apache.tomcat.util.net.DispatchType;
import org.apache.tomcat.util.net.SocketEvent;
import org.apache.tomcat.util.net.SocketWrapperBase;

/**
 * This is a light-weight abstract processor implementation that is intended as
 * a basis for all Processor implementations from the light-weight upgrade
 * processors to the HTTP/AJP processors.
 */
public abstract class AbstractProcessorLight implements Processor {

    private Set<DispatchType> dispatches = new CopyOnWriteArraySet<>();


    @Override
    public SocketState process(SocketWrapperBase<?> socketWrapper, SocketEvent status)
            throws IOException {

        //Socket客户端状态。
        SocketState state = SocketState.CLOSED;
        //需要分配执行的客户端请求。
        Iterator<DispatchType> dispatches = null;
        do {
            if (dispatches != null) {//如果分派执行不为空，则分派执行当前客户端请求。
                DispatchType nextDispatch = dispatches.next();
                if (getLog().isDebugEnabled()) {
                    getLog().debug("Processing dispatch type: [" + nextDispatch + "]");
                }
                //调用dispatch抽象方法完成分派，该方法由子类实现，完成非标准HTTP的分派，目前该方法用于实现了Tomcat对于协议升级和Servlet 3.0异步的支持。
                state = dispatch(nextDispatch.getSocketStatus());
                //如果分配请求到达最后一个，则需要检查是否需要继续读取数据，state为当前分配执行的客户端状态。
                if (!dispatches.hasNext()) {
                    state = checkForPipelinedData(state, socketWrapper);
                }
            } else if (status == SocketEvent.DISCONNECT) {//客户端断开连接，则不执行任何操作，相关资源会在调用该方法后回收。
                // Do nothing here, just wait for it to get recycled
            } else if (isAsync() || isUpgrade() || state == SocketState.ASYNC_END) {//如果当前处理器为异步处理或者协议升级，或者状态为异步执行结束ASYNC_END，那么需要调用子类实现的dispatch操作，完成异步或者协议处理。
                state = dispatch(status);
                //同样，分派处理后需要检测是否有数据继续读取。
                state = checkForPipelinedData(state, socketWrapper);
            } else if (status == SocketEvent.OPEN_WRITE) {//在异步处理之后可能会有额外的写入事件，此时，仅设置LONG，由ConnectionHandler处理该连接，此时表明连接处于连接状态，如果这时处于非异步状态，那么会注册读感兴趣事件，继续读取客户端内容。
                // Extra write event likely after async, ignore
                state = SocketState.LONG;
            } else if (status == SocketEvent.OPEN_READ) {//如果是读事件，则调用service方法完成对标准HTTP请求的处理。
                state = service(socketWrapper);
            } else if (status == SocketEvent.CONNECT_FAIL) {//连接失败事件，则记录日志。
                logAccess(socketWrapper);
            } else {//默认状态为连接关闭。
                // Default to closing the socket if the SocketEvent passed in
                // is not consistent with the current state of the Processor
                state = SocketState.CLOSED;
            }

            if (getLog().isDebugEnabled()) {
                getLog().debug("Socket: [" + socketWrapper +
                        "], Status in: [" + status +
                        "], State out: [" + state + "]");
            }

            //异步处理器，则调用asyncPostProcess方法完成异步处理。
            if (isAsync()) {
                state = asyncPostProcess();
                if (getLog().isDebugEnabled()) {
                    getLog().debug("Socket: [" + socketWrapper +
                            "], State after async post processing: [" + state + "]");
                }
            }

            //如果处理完成，请求分配为空，则通过方法getIteratorAndClearDispatches方法获取新的分派类型。
            if (dispatches == null || !dispatches.hasNext()) {
                // Only returns non-null iterator if there are
                // dispatches to process.
                dispatches = getIteratorAndClearDispatches();
            }
        } while (state == SocketState.ASYNC_END ||//异步完成状态继续循环。
                dispatches != null && state != SocketState.CLOSED);//分配未完成且状态不为CLOSED，也即客户端未关闭，则也继续循环。

        //返回处理的状态。
        return state;
    }


    private SocketState checkForPipelinedData(SocketState inState, SocketWrapperBase<?> socketWrapper)
            throws IOException {
        if (inState == SocketState.OPEN) {
            // There may be pipe-lined data to read. If the data isn't
            // processed now, execution will exit this loop and call
            // release() which will recycle the processor (and input
            // buffer) deleting any pipe-lined data. To avoid this,
            // process it now.
            return service(socketWrapper);
        } else {
            return inState;
        }
    }


    public void addDispatch(DispatchType dispatchType) {
        synchronized (dispatches) {
            dispatches.add(dispatchType);
        }
    }


    public Iterator<DispatchType> getIteratorAndClearDispatches() {
        // Note: Logic in AbstractProtocol depends on this method only returning
        // a non-null value if the iterator is non-empty. i.e. it should never
        // return an empty iterator.
        Iterator<DispatchType> result;
        synchronized (dispatches) {
            // Synchronized as the generation of the iterator and the clearing
            // of dispatches needs to be an atomic operation.
            result = dispatches.iterator();
            if (result.hasNext()) {
                dispatches.clear();
            } else {
                result = null;
            }
        }
        return result;
    }


    protected void clearDispatches() {
        synchronized (dispatches) {
            dispatches.clear();
        }
    }


    /**
     * Add an entry to the access log for a failed connection attempt.
     *
     * @param socketWrapper The connection to process
     *
     * @throws IOException If an I/O error occurs during the processing of the
     *         request
     */
    protected void logAccess(SocketWrapperBase<?> socketWrapper) throws IOException {//由子类实现。
        // NO-OP by default
    }


    /**
     * Service a 'standard' HTTP request. This method is called for both new
     * requests and for requests that have partially read the HTTP request line
     * or HTTP headers. Once the headers have been fully read this method is not
     * called again until there is a new HTTP request to process. Note that the
     * request type may change during processing which may result in one or more
     * calls to {@link #dispatch(SocketEvent)}. Requests may be pipe-lined.
     *
     * @param socketWrapper The connection to process
     *
     * @return The state the caller should put the socket in when this method
     *         returns
     *
     * @throws IOException If an I/O error occurs during the processing of the
     *         request
     */
    protected abstract SocketState service(SocketWrapperBase<?> socketWrapper) throws IOException;//由子类实现。

    /**
     * Process an in-progress request that is not longer in standard HTTP mode.
     * Uses currently include Servlet 3.0 Async and HTTP upgrade connections.
     * Further uses may be added in the future. These will typically start as
     * HTTP requests.
     *
     * @param status The event to process
     *
     * @return The state the caller should put the socket in when this method
     *         returns
     *
     * @throws IOException If an I/O error occurs during the processing of the
     *         request
     */
    protected abstract SocketState dispatch(SocketEvent status) throws IOException;//由子类实现。

    protected abstract SocketState asyncPostProcess();//由子类实现。

    protected abstract Log getLog();//由子类实现。
}
